#include "include.h"

#if BT_SPEEX_EN

#define SPX_CACHE_LEN       4000
#define SPX_FRAME_LEN       20

struct spx_cb_t {
    u8 togle;
    u8 sysclk;
    u16 wptr;
    u16 rptr;
    volatile u16 len;
    u8 output[SPX_CACHE_LEN];
} spx_cb  AT(.speex.pcm);

static u8 spx_start = 0;

void speex_put_pcm(u8 *buf, u16 len);
void spx_kick_start(void);
void plugin_app_tx(u8 *buf, u16 len);
void speex_enc_init(void);
void speex_enc_exit(void);

//缓存压缩好的数据
AT(.text.speex.frame)
void speex_put_frame(u8 *buf, u16 len)
{
    struct spx_cb_t * p = &spx_cb;
    if (p->len <= (SPX_CACHE_LEN - len)) {
        if ((SPX_CACHE_LEN - p->wptr) >= len) {
            memcpy(&p->output[p->wptr], buf, len);
            p->wptr += len;
            if (p->wptr >= SPX_CACHE_LEN) {
                p->wptr = 0;
            }
        } else {
            u16 rest = SPX_CACHE_LEN - p->wptr;
            memcpy(&p->output[p->wptr], buf, rest);
            p->wptr = 0;
            memcpy(&p->output[p->wptr], &buf[rest], len - rest);
            p->wptr += len - rest;
        }
        GLOBAL_INT_DISABLE();
        p->len += len;
        GLOBAL_INT_RESTORE();
    }

    bsp_spx_process();
}

AT(.com_text.speex.frame)
void speex_sdadc_process(u8 *ptr, u32 samples, int ch_mode)
{
#if 0
    //SPEEX测试代码
	#define FRAME       512
    static u16 cnt = FRAME;
    u32 res_addr = RES_BUF_INFILE_BIN;
    if (cnt) {
        memcpy(ptr, (u8 *)(res_addr + 160 * (FRAME - cnt)), 160);
        cnt--;
    } else {
        return;
    }
#endif
    speex_put_pcm(ptr, samples);
    if (spx_cb.togle) {
        spx_kick_start();
    }
    spx_cb.togle ^= 1;
}

AT(.text.speex.frame)
void bsp_spx_process(void)
{
    struct spx_cb_t * p = &spx_cb;
    if (spx_start == 0) {
        return;
    } else if ((spx_start & BIT(1)) == 0) {
        if (p->len < SPX_FRAME_LEN) {
            spx_start = 0;
            return;
        }
    }
    if (p->len < SPX_FRAME_LEN) {     //1帧
        return;
    }

//    plugin_app_tx(&p->output[p->rptr], SPX_FRAME_LEN);
    p->rptr += SPX_FRAME_LEN;
    if (p->rptr >= SPX_CACHE_LEN) {
        p->rptr = 0;
    }
    GLOBAL_INT_DISABLE();
    p->len -= SPX_FRAME_LEN;
    GLOBAL_INT_RESTORE();
}

void bsp_spx_init(void)
{
    memset(&spx_cb, 0, sizeof(struct spx_cb_t));
    spx_cb.sysclk = get_cur_sysclk();
    set_sys_clk(SYS_120M);
    speex_enc_init();
    spx_start = 0x03;
    audio_path_init(AUDIO_PATH_SPEEX);
    audio_path_start(AUDIO_PATH_SPEEX);
}

void bsp_spx_exit(void)
{
    spx_start &= ~BIT(1);
    audio_path_exit(AUDIO_PATH_SPEEX);
    speex_enc_exit();
    set_sys_clk(spx_cb.sysclk);
}
#else
void speex_put_frame(u8 *buf, u16 len) {}
#endif
